package network;

import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;
import java.io.PrintWriter;
import java.net.ServerSocket;
import java.net.Socket;
import java.util.Scanner;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;

/**
 * Created with IntelliJ IDEA.
 * Description:
 * User: Home-pc
 * Date: 2023-10-04
 * Time: 10:52
 */
//基于TCP的回显服务器
public class TcpEachServer {
    private ServerSocket serverSocket=null;
    //创建一个非固定数目的线程池
    private ExecutorService service= Executors.newCachedThreadPool();

    //绑定端口号
    public  TcpEachServer(int port) throws IOException {
        serverSocket=new ServerSocket(port);
    }

    //启动服务器
    public  void  start() throws IOException {
        System.out.println("服务器开始启动");
        while(true){
            //从管理连接的队列中拿出一个“连接”出来
            Socket clientSocket=serverSocket.accept();
            //处理这个连接内的请求
            service.submit(new Runnable() {
                @Override
                public void run() {
                    try {
                        processConnection(clientSocket);
                    } catch (IOException e) {
                        e.printStackTrace();
                    }
                }
            });
/*            Thread t=new Thread(() ->{
                try {
                    processConnection(clientSocket);
                } catch (IOException e) {
                    e.printStackTrace();
                }
            });
            t.start();*/
        }
    }
    //这个方法用来处理连接中的逻辑
    private void processConnection(Socket clientSocket) throws IOException {
        //日志
        System.out.printf("[%s:%d] 客户端上线\n",clientSocket.getInetAddress().toString(),
                clientSocket.getPort());
        //下面开始读取请求，计算响应，返回响应  三步曲
        //Socket对象内部包含两种字节流对象InputStream和OutputStream，可以先把这两个对象流获
        // 取到，方便后续处理过程种的读写工作
        try(InputStream inputStream=clientSocket.getInputStream();
            OutputStream outputStream=clientSocket.getOutputStream()){
            //不同于UDP协议中的无连接，在客户端的一次连接过程中，可能涉及多次请求/响应过程
            //因此。这里使用一个while循环，直到该连接中的所有请求处理完毕
            while(true){
                //1，读取请求并解析
                Scanner scanner=new Scanner(inputStream);
                //hasNext的作用是，检测输入流中是否有结束输入的控制符，比如0x1A(EOF,Ctrl-Z)
                //用于检测一个连接是否结束
                if(!scanner.hasNext()){
                    //一个连接处理完毕
                    System.out.printf("[%s:%d] 客户端本次连接处理完毕，下线！\n",clientSocket.getInetAddress().toString(),
                            clientSocket.getPort());
                    break;
                }
                // 这个代码暗含一个约定, 客户端发过来的请求, 得是文本数据, 同时, 还得带有空白符作为分割. (比如换行这种)
                //next()：当输入到空白符结束
                String request=scanner.next();
                //2.根据请求计算响应
               String response=process(request);
               //3. 把响应写回客户端，把OutputStream用PrintWriter(此处的PrintWriter相当于Scanner)包裹一下，便于发送数据
                //将outputStream和PrintWriter关联起来
                PrintWriter writer=new PrintWriter(outputStream);
                //使用 PrintWriter 的 println 方法,打印到输出流中 把响应返回给客户端.
                //此处用 println, 而不是 print 就是为了在结尾加上 \n . 方便客户端读取响应, 使用 scanner.next 读取.
                writer.println(response);
                //这里还需要加一个 "刷新缓冲区" 操作.将缓冲区的数据强制输出，用于清空缓冲区
                writer.flush();

                //日志 记录当前的请求和响应
                System.out.printf("[%s:%d]  req: %s,resp: %s\n",clientSocket.getInetAddress().toString(),
                        clientSocket.getPort(),request,response);
            }
        } finally {
            clientSocket.close();
        }
    }

    //回显，只需要再返回这个字符串
    public String process(String requset){
        return requset;
    }
    public static void main(String[] args) throws IOException {
        TcpEachServer tcpEachServer=new TcpEachServer(9090);
        tcpEachServer.start();
    }
}
